package com.gitee.aleenjava.aliyun.mqtt.register;

import com.gitee.aleenjava.aliyun.mqtt.annotation.MqttSubscriber;
import com.gitee.aleenjava.aliyun.mqtt.model.SubscriberInfo;
import com.gitee.aleenjava.aliyun.mqtt.processor.MqttSubscribeProcessor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;

import java.util.*;


/**
 * @author cheng
 */
public class MqttSubscriberRegister implements ApplicationContextAware, PriorityOrdered, BeanFactoryPostProcessor {

    private ConfigurableApplicationContext applicationContext;

    private List<SubscriberInfo> subscriberInfos = new ArrayList<SubscriberInfo>();


    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        String[] mqttSubscriberBeanNames = beanFactory.getBeanNamesForAnnotation(MqttSubscriber.class);
        Map<String, Class<?>> allTopicRef = new HashMap<>(mqttSubscriberBeanNames.length);
        for (String mqttSubscriberBeanName : mqttSubscriberBeanNames) {
            Class<?> mqttSubscriberClazz = beanFactory.getType(mqttSubscriberBeanName);
            Class<?>[] interfaces = mqttSubscriberClazz.getInterfaces();
            if (Arrays.stream(interfaces).noneMatch(i -> i == MqttSubscribeProcessor.class)) {
                throw new IllegalArgumentException("mqtt SubscribeProcessor must implements MqttSubscribeProcessor, problem class : {" + mqttSubscriberClazz.getName() + "}");
            }
            MqttSubscriber mqttSubscriber = mqttSubscriberClazz.getAnnotation(MqttSubscriber.class);
            String topic = applicationContext.getEnvironment().resolveRequiredPlaceholders(mqttSubscriber.topic());
            for (String historyTopic : allTopicRef.keySet()) {
                if (validate(historyTopic, topic)) {
                    throw new IllegalArgumentException("mqtt Do not allow duplicate or related topic subscriptions, conflict definitions: " + "{" + historyTopic + ", " + topic + "}," + "{" + allTopicRef.get(historyTopic).getName() + ", " + mqttSubscriberClazz.getName() + "}");
                }
            }
            allTopicRef.put(topic, mqttSubscriberClazz);
            subscriberInfos.add(SubscriberInfo.builder().topic(topic).qos(mqttSubscriber.qos()).mqttSubscribeProcessor((MqttSubscribeProcessor) applicationContext.getBean(mqttSubscriberBeanName)).build());
        }
    }

    private boolean validate(String topic1, String topic2) {
        if (!topic1.equals(topic2)) {
            return false;
        } else {
            return true;
        }
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = (ConfigurableApplicationContext) applicationContext;
    }

    public List<SubscriberInfo> getSubscriberInfos() {
        return subscriberInfos;
    }

    public void setSubscriberInfos(List<SubscriberInfo> subscriberInfos) {
        this.subscriberInfos = subscriberInfos;
    }

}
